'''
Author: xialang333@gmail.com
Date: 2024-07-26 16:50:10
LastEditTime: 2024-08-02 17:55:25
'''
import os
import datetime
import paramiko
from django_q.tasks import async_task
from rest_framework import serializers
from utils.viewset import CustomModelViewSet
from utils.serializers import CustomModelSerializer
from utils.jsonResponse import DetailResponse, ErrorResponse

from apps.crond.views.task import scheduler
from application.settings import BASE_DIR
from apps.lywebsocket.models import TerminalServer
from apps.software.models import ApplicationDepLogs, ApplicationModel


class ApplicationDepLogsSerializer(CustomModelSerializer):
    app = serializers.CharField(source='ApplicationModel.name', read_only=True)
    ver = serializers.CharField(source='ApplicationModel.ver', read_only=True)
    
    class Meta:
        model = ApplicationDepLogs
        fields = ('app', 'ver','ipaddr','status','logs')




class ApplicationModelSerializer(CustomModelSerializer):
    class Meta:
        model = ApplicationModel
        exclude = ['dept_belong_id', 'modifier', 'creator']
        read_only_fields = ["id"]


class ApplicationViewSet(CustomModelViewSet):
    queryset = ApplicationModel.objects.all()
    serializer_class = ApplicationModelSerializer
    search_fields = ('id', 'name')


class ApplicationDepLogsViewSet(CustomModelViewSet):
    queryset = ApplicationDepLogs.objects.all()
    serializer_class = ApplicationDepLogsSerializer
    search_fields = ('id', 'name')

    # 执行部署操作
    def deploy_app_exec(self, request, *args, **kwargs):
        try:
            data = request.data
            run_date = datetime.datetime.now() + datetime.timedelta(seconds=5)
            if scheduler.state == 0:
                scheduler.start()
            job = scheduler.add_job(task, 'date', run_date=run_date, args=[data,])
            return DetailResponse(data=None, msg="执行成功")
        except Exception as e:
            return ErrorResponse(data=None, msg=f"执行失败: {str(e)}")


def task(data):
    deployAppHandler(data).main()

class deployAppHandler:
    
    def __init__(self, data):
        self.host_ids = data["host_ids"]
        self.app_id = data["app_id"]
        self.file_name = None
    
    # 获取服务器信息
    def getHosts(self):
        host_info = []
        for _i in self.host_ids:
            _obj = TerminalServer.objects.get(id=_i)
            host_info.append(_obj)
        return host_info
    
    # 获取部署信息
    def getApp(self):
        return ApplicationModel.objects.get(id=self.app_id)
    
    def main(self):
        app_deploy_info = self.getApp()
        host_info = self.getHosts()
        tempfile_path = os.path.join(BASE_DIR, "media")
        self.file_name = f'{app_deploy_info.name}-{app_deploy_info.ver}.sh'
        file = str(tempfile_path)+"/"+f'{app_deploy_info.name}-{app_deploy_info.ver}.sh'
        with open(file, 'w') as f:
            f.write(app_deploy_info.deployment)
        for i in host_info:
            a_obj = ApplicationDepLogs.objects.create(appserver=app_deploy_info, ipaddr=i.host)
            res = self.sshExec(info=i, file=file)
            a_obj.logs = res
            a_obj.status = 0
            a_obj.save()

    
    # 远程执行
    def sshExec(self, info, file):
        try:
            exec_result = ''
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            if info.type == 0:
                ssh.connect(hostname=info.host, username=info.username, port=info.port, password=info.password)
            elif info.type == 1:
                tmppkey = info.pkey.encode('utf-8')
                if sys.version_info[0] == 2:
                    p_file = BytesIO(tmppkey)
                else:
                    p_file = StringIO(tmppkey)
                pkey = paramiko.RSAKey.from_private_key(p_file)
                ssh.connect(
                    hostname=info.host,
                    port=info.port,
                    username=info.username,
                    pkey=pkey
                )
            sftp = paramiko.SFTPClient.from_transport(ssh.get_transport())
            remote_file_path = "/tmp/" + self.file_name
            sftp.put(file, remote_file_path)
            sftp.close()
            ssh.exec_command(f"chmod +x {remote_file_path}")
            command = f"sh {remote_file_path}"
            # 务必要加上get_pty=True,否则执行命令会没有权限
            stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)
            # result = stdout.read()
            # 循环发送消息给前端页面
            while True:
                nextline = stdout.readline().strip()  # 读取脚本输出内容
                # print(nextline.strip())
                exec_result += nextline
                # 判断消息为空时,退出循环
                if not nextline:
                    break

            ssh.close()  # 关闭ssh连接
            return exec_result
        except Exception as e:
            return str(e)
